package com.darco.darcoapp;

import static DARCOShared.utils.Constants.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyPair;
import java.util.ArrayList;
import java.util.UUID;

import com.darco.darcoapp.interfaces.IGeoLocatingActivity;

import DARCOShared.requests.ChangeOwnershipRequest;
import DARCOShared.requests.GetCardInfoRequest;
import DARCOShared.requests.RequestBase;
import DARCOShared.requests.RequestType;
import DARCOShared.responses.ChangeOwnershipResponse;
import DARCOShared.responses.GetCardInfoResponse;
import DARCOShared.responses.ResponseBase;
import DARCOShared.responses.ResponseType;
import DARCOShared.responses.ResponseWrapper;
import DARCOShared.utils.Base64;
import DARCOShared.utils.Constants;
import DARCOShared.utils.SecurityUtilities;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import eneter.messaging.endpoints.typedmessages.TypedResponseReceivedEventArgs;


public class BluetoothManager extends MessagingActivity implements OnItemClickListener, IGeoLocatingActivity {
	private MessagingManager mm;
	private BluetoothAdapter myBluetoothAdapter;
	private BroadcastReceiver myReceiver;
	private ConnectThread myConnectThread;
	private AcceptThread myAcceptThread;
	private ConnectedThread myConnectedThread;
	private static MyStaticHandler myHandler;
	private int MODE;
	private ArrayList<String> myDevicesList;
	private ArrayList<BluetoothDevice> myBTDevicesList;
	private ArrayAdapter<String> myDevicesListAdapter;
	private byte[] tradeSignature;
	private ContentValues myAccountInfo;
	private ContentValues mySystemInfo;
	private boolean geolocate;
	private GetCardInfoResponse myCardInfoResponse;
	private GeolocationHelper myGeoLocationHelper;
	private GetCardInfoResponse myNewCardInfo;

	private static final int REQUEST_ENABLE_BT = 98;
	private static final int REQUEST_ENABLE_BT_DISCOVERABLE = 99;
	public static final int REQUEST_SKIP = 97;


	public static final int SCAN_CANCELED = 1;
	public static final int NO_BT = 2;
	public static final int BT_NOT_ENABLED = 3;
	public static final int BT_DISCOVERABILITY_NOT_ENABLED = 4;

	public static final int INTENT_SCAN_AND_SEND = 50;
	public static final int INTENT_LISTEN_AND_RECEIVE = 51;

	public static final int TRADE_SUCCESSFUL = 60;
	public static final int TRADE_FAILED = 61;

	public static final int FAILED_BAD_SIGNATURE = 70;
	public static final int FAILED_SENDER_CANCELED = 71;
	public static final int FAILED_RECEIVER_CANCELED = 72;
	public static final int FAILED_SERVER_REFUSED = 73;
	public static final int FAILED_CARD_NOT_AUTHENTICATED = 74;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		myAccountInfo = (ContentValues) getIntent().getExtras().get("account");
		mySystemInfo = (ContentValues) getIntent().getExtras().get("system");
		geolocate = (mySystemInfo.getAsInteger(SYSTEM_ALLOWLOCATION) == 1 ? true : false); //TODO: solo per test
		myGeoLocationHelper = new GeolocationHelper(this);

		MODE = getIntent().getIntExtra("mode", INTENT_SCAN_AND_SEND);
		myHandler = new MyStaticHandler() {
			@Override
			public void handleMessage(Message msg) {
				incomingData(msg);
			}
		};


		tradeSignature= null;
		myBTDevicesList = new ArrayList<BluetoothDevice>();
		myDevicesList = new ArrayList<String>();
		myDevicesListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, myDevicesList);

		setContentView(R.layout.activity_bluetoothmanager);

		ListView lv = (ListView)(findViewById(R.id.devicesList));
		lv.setAdapter(myDevicesListAdapter);


		lv.setOnItemClickListener(this);  

		if(MODE == INTENT_LISTEN_AND_RECEIVE){
			TextView tv = (TextView)findViewById(R.id.bluetoothTitle);
			tv.setText(getString(R.string.btmanager_title_receiver));
			tv = (TextView)findViewById(R.id.bluetoothSubtitle);
			tv.setText(getString(R.string.btmanager_header_receiver));
		}
		else{
			TextView tv = (TextView)findViewById(R.id.bluetoothTitle);
			tv.setText(getString(R.string.btmanager_title_sender));
			tv = (TextView)findViewById(R.id.bluetoothSubtitle);
			tv.setText(getString(R.string.btmanager_header_sender));
		}

		tryEnableBluetooth();
	}

	private void incomingData(Message msg) {
		byte[] buf = (byte[])(msg.obj);
		String message = new String(buf).substring(0, msg.arg1);
		String[] data = message.split("\\$");

		if(data[0].equals("accepted")){
			showAcceptedPopup();
			return;
		}
		if(data[0].equals("rejected")){
			showFailedPopup(FAILED_RECEIVER_CANCELED);
			return;
		}
		if(data[0].equals("failed")){
			showFailedPopup(Integer.parseInt(data[1]));
			return;
		}

		if(MODE == INTENT_LISTEN_AND_RECEIVE){

			if(data[0].equals("who_are_you?")){
				geolocate = geolocate && (data[1].equals("geolocateOn"));
				myConnectedThread.write("identity$" + myAccountInfo.getAsString(Constants.ACCOUNT_EMAIL) + "$" + (geolocate ? "geolocateOn" : "geolocateOff"));
				return;
			}			
			if(data[0].equals("card_incoming")){
				String cardSN = data[1];
				String cardUID = data[2];
				try {
					tradeSignature = Base64.decode(data[3]);
				} catch (IOException e) {
					e.printStackTrace();
				}

				GetCardInfoRequest req = new GetCardInfoRequest(cardSN, cardUID);
				onPerformRequest(req);
				return;
			}
		}
		else{
			if(data[0].equals("identity")){
				geolocate = geolocate && (data[2].equals("geolocateOn"));
				String cardSN = getIntent().getExtras().getString("cardSN");
				String cardUID = getIntent().getExtras().getString("cardUniqueID");
				KeyPair myKP = SecurityUtilities.Bin2KeyPair(myAccountInfo.getAsByteArray(Constants.ACCOUNT_KEYPAIR));
				byte[] signature = SecurityUtilities.signData((cardSN + cardUID + data[1]).getBytes(), myKP.getPrivate()); 

				String encodedSig = Base64.encodeBytes(signature);
				myConnectedThread.write("card_incoming$" + cardSN + "$" + cardUID + "$" + encodedSig);
				return;
			}

		}
	}

	public void tryEnableBluetooth(){
		myBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

		//device doesn't have BT :/
		if (myBluetoothAdapter == null) {
			showNoBluetoothAlert(NO_BT);
		}

		//we want to send
		if(MODE == INTENT_SCAN_AND_SEND){
			if (!myBluetoothAdapter.isEnabled()) {
				//We are the sender of the card, start scanning for devices
				Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
				startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
				return;
			}
			else{
				//bluetooth already on
				scanForDevices();
				return;
			}

		}

		//we want to receive
		else{
			//We are the receiver of the card, become visible and start listening
			Intent discoverableIntent = new	Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
			discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 150);
			startActivityForResult(discoverableIntent, REQUEST_ENABLE_BT_DISCOVERABLE);
			showLoadingDialog("Waiting for card", "Waiting for the owner to send the card...");
			return;
		}
	}


	@Override
	protected void onActivityResult (int requestCode, int resultCode, Intent data){
		if(requestCode == REQUEST_SKIP){
			finish();
		}
		
		if (requestCode == REQUEST_ENABLE_BT){
			if(resultCode == RESULT_OK){
				//bluetooth attivo
				scanForDevices();
			}
			else{
				//bluetooth non attivato
				showNoBluetoothAlert(BT_NOT_ENABLED);
			}
			return;
		}

		if (requestCode == REQUEST_ENABLE_BT_DISCOVERABLE){
			if(resultCode != RESULT_CANCELED){
				startListening();
			}
			else{
				//discoverability not enabled
				showNoBluetoothAlert(BT_DISCOVERABILITY_NOT_ENABLED);
			}
			return;
		}

		super.onActivityResult(requestCode, resultCode, data);
	}


	private void startListening() {
		killConnectedThread();
		killAcceptThread();
		myAcceptThread = new AcceptThread();
		myAcceptThread.start();
	}

	///starts discovering nearby bluetooth devices
	private void scanForDevices() {
		myReceiver = new BroadcastReceiver() {
			public void onReceive(Context context, Intent intent) {
				String action = intent.getAction();
				// When discovery finds a device
				if (BluetoothDevice.ACTION_FOUND.equals(action)) {
					// Get the BluetoothDevice object from the Intent
					BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
					// Add the name and address to an array adapter to show in a ListView
					//mArrayAdapter.add(device.getName() + "\n" + device.getAddress());
					myDevicesList.add(device.getName());
					myBTDevicesList.add(device);

					myDevicesListAdapter.notifyDataSetChanged();
				}
			}
		};
		//Register the BroadcastReceiver
		IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
		registerReceiver(myReceiver, filter); // Don't forget to unregister during onDestroy

		myBluetoothAdapter.startDiscovery();
	}


	///Shows message popup informing user that the app cannot proceed if bluetooth is disabled
	private void showNoBluetoothAlert(final int why){
		hideLoadingDialog();
		AlertDialog dialogBox = new AlertDialog.Builder(this).create();
		dialogBox.setTitle("Bluetooth problem");
		if(why == NO_BT)
			dialogBox.setMessage("Your device does not have Bluetooth. You cannot use the trading feature, sorry :(");
		if(why == BT_NOT_ENABLED)
			dialogBox.setMessage("You did not enable Bluetooth. Bluetooth is needed for trading cards!\n You will be sent back to the trading menu.");
		if(why == BT_DISCOVERABILITY_NOT_ENABLED)
			dialogBox.setMessage("You did not become visible. Device Discoverability is essential if you want to trade.\nYou will be brought back, please try again.");
		dialogBox.setButton("Ok",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				//return to trading activity
				//finishActivity(why);
				Intent in = getIntent();
				setResult(why, in);
				finish();
			}
		});
		dialogBox.show();
	}

	private void showConfirmationPopup(){
		hideLoadingDialog();
		AlertDialog dialogBox = new AlertDialog.Builder(this).create();
		dialogBox.setTitle("Card incoming");
		dialogBox.setMessage("You are being offered the following card:\n" +
				"Card name: " + myCardInfoResponse.cardName + "\n" +
				"Card type:" + myCardInfoResponse.categoryName + "\n\n" +
				"The owner of the card has been verified by the server. If you click \"Yes\" you will become the owner of this card.\n\n" +
				"Accept the trade?");
		dialogBox.setButton("Yes",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
						        
				if(geolocate && myGeoLocationHelper.isLocationEnabled()){
					showLoadingDialog("Getting position", "Trying to obtain your position through GPS. This could take a while...");
					myGeoLocationHelper.startGeoLocating();
				}
				else{
					onPerformRequest(new ChangeOwnershipRequest(myCardInfoResponse.cardSN, myCardInfoResponse.cardID, myAccountInfo.getAsString(Constants.ACCOUNT_EMAIL), tradeSignature));
				}

			}
		});

		dialogBox.setButton2("No",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				myConnectedThread.write("rejected");
				showFailedPopup(FAILED_RECEIVER_CANCELED);
			}
		});

		dialogBox.show();
	}

	///Shows message popup informing user that the app cannot proceed if bluetooth is disabled
	private void showAcceptedPopup(){
		hideLoadingDialog();
		AlertDialog dialogBox = new AlertDialog.Builder(this).create();
		dialogBox.setTitle("Trade was succesful!");
		if(MODE == INTENT_SCAN_AND_SEND)
			dialogBox.setMessage("You have sent the card, and do not own it anymore. It will be deleted from your local store.\n");
		if(MODE == INTENT_LISTEN_AND_RECEIVE)
			dialogBox.setMessage("You have received the card! It will be added to your repository.");
		dialogBox.setButton("Ok",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				//return to trading activity
				
				if(MODE == INTENT_LISTEN_AND_RECEIVE){
					Intent i = new Intent(BluetoothManager.this, Visualization_Activity.class);
					i.putExtra("cardInfo", buildCardValuesFromResponse(myNewCardInfo));
					i.putExtra("uniqueInfo", buildUniqueCardValuesFromResponse(myNewCardInfo));
					i.putExtra("account", myAccountInfo);
					i.putExtra("system", mySystemInfo);
					i.putExtra(VISUALIZATION_ORIGIN, VISUALIZATION_FROM_BT_RECEIVE);
					startActivityForResult(i, REQUEST_SKIP);
				}
				else{
					Intent i = getIntent();
					setResult(TRADE_SUCCESSFUL, i);
					finish();
				}
			}
		});
		dialogBox.show();
	}
	

	///Shows message popup informing user that the app cannot proceed if bluetooth is disabled
	private void showFailedPopup(int why){
		hideLoadingDialog();
		AlertDialog dialogBox = new AlertDialog.Builder(this).create();
		dialogBox.setTitle("Trade was canceled!");
		if(why == FAILED_RECEIVER_CANCELED && MODE == INTENT_SCAN_AND_SEND)
			dialogBox.setMessage("The receiver has refused the trade. You still have possession of your card. You can try again later if you want.");
		if(why == FAILED_RECEIVER_CANCELED && MODE == INTENT_LISTEN_AND_RECEIVE)
			dialogBox.setMessage("You have refused the trade and you have not received the card. You will now get back");
		if(why == FAILED_BAD_SIGNATURE){
			if(MODE == INTENT_SCAN_AND_SEND)
				dialogBox.setMessage("Signature error! You are not the owner of this card, and therefore cannot trade it! Cheater!!");
			else
				dialogBox.setMessage("The sender's signature verification failed. This means that the sender is not the real owner of this card, and is trying to scam you!!");
		}
		if(why == FAILED_CARD_NOT_AUTHENTICATED)
			dialogBox.setMessage("This card is not authenticated! Transaction failed!");
		if(why == FAILED_SERVER_REFUSED)
			dialogBox.setMessage("Trade failed, the server refused the transaction!");
		dialogBox.setButton("Ok",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				//return to trading activity
				Intent in = getIntent();
				setResult(TRADE_FAILED, in);
				finish();
			}
		});
		dialogBox.show();
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
		myBluetoothAdapter.cancelDiscovery();

		BluetoothDevice dev = myBTDevicesList.get(position);
		killConnectedThread();
		killConnectThread();
		showLoadingDialog("Trading", "Contacting recipient and performing trade, please wait...");
		myConnectThread = new ConnectThread(dev);
		myConnectThread.start();		
	}


	//Destroyer
	@Override
	protected void onDestroy() {
		super.onDestroy();

		killThreads();

		try {
			unregisterReceiver(myReceiver);
		} catch (Exception e) {

		}

	}


	//////////////////////////////////////////
	// Thread for the receiver to listen on //
	//////////////////////////////////////////
	private class AcceptThread extends Thread {
		private final BluetoothServerSocket mmServerSocket;

		public AcceptThread() {
			// Use a temporary object that is later assigned to mmServerSocket,
			// because mmServerSocket is final
			BluetoothServerSocket tmp = null;
			try {
				tmp = myBluetoothAdapter.listenUsingRfcommWithServiceRecord("darco", UUID.fromString("3fd14c2a-184c-46c7-8973-9d8c4a6ebb76"));
			} catch (IOException e) {
				e.printStackTrace();
			}
			mmServerSocket = tmp;
		}

		public void run() {
			BluetoothSocket socket = null;
			// Keep listening until exception occurs or a socket is returned
			while (true) {
				try {
					socket = mmServerSocket.accept();
				} catch (IOException e) {
					e.printStackTrace();
					break;
				}
				// If a connection was accepted
				if (socket != null) {
					// Do work to manage the connection (in a separate thread)
					manageConnectedSocket(socket);
					try {
						mmServerSocket.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
					break;
				}
			}
		}

		/** Will cancel the listening socket, and cause the thread to finish */
		public void cancel() {
			try {
				mmServerSocket.close();
			} catch (IOException e) { 

			}
		}
	}


	//////////////////////////////////////
	// Thread for the sender to connect //
	//////////////////////////////////////
	private class ConnectThread extends Thread {
		private final BluetoothSocket mmSocket;
		private final BluetoothDevice mmDevice;

		public ConnectThread(BluetoothDevice device) {
			// Use a temporary object that is later assigned to mmSocket,
			// because mmSocket is final
			BluetoothSocket tmp = null;
			mmDevice = device;

			// Get a BluetoothSocket to connect with the given BluetoothDevice
			try {
				// MY_UUID is the app's UUID string, also used by the server code
				tmp = mmDevice.createRfcommSocketToServiceRecord(UUID.fromString("3fd14c2a-184c-46c7-8973-9d8c4a6ebb76"));
			} catch (IOException e) { 
				e.printStackTrace();
			}
			mmSocket = tmp;
		}

		public void run() {
			// Cancel discovery because it will slow down the connection
			myBluetoothAdapter.cancelDiscovery();

			try {
				// Connect the device through the socket. This will block
				// until it succeeds or throws an exception
				mmSocket.connect();
			} catch (IOException connectException) {
				// Unable to connect; close the socket and get out
				try {
					mmSocket.close();
				} catch (IOException closeException) {
					closeException.printStackTrace();
				}
				return;
			}

			// Do work to manage the connection (in a separate thread)
			manageConnectedSocket(mmSocket);
		}

		/** Will cancel an in-progress connection, and close the socket */
		public void cancel() {
			try {
				mmSocket.close();
			} catch (IOException e) { }
		}
	}


	private void manageConnectedSocket(BluetoothSocket socket) {
		killConnectedThread();
		myConnectedThread = new ConnectedThread(socket);
		myConnectedThread.start();	

		if(MODE == INTENT_SCAN_AND_SEND){
			myConnectedThread.write("who_are_you?"+ "$" + (geolocate ? "geolocateOn" : "geolocateOff"));
			//myConnectedThread.write("who_are_you?");
		}
	}


	private class ConnectedThread extends Thread {
		private final BluetoothSocket mmSocket;
		private final InputStream mmInStream;
		private final OutputStream mmOutStream;

		public ConnectedThread(BluetoothSocket socket) {
			mmSocket = socket;
			InputStream tmpIn = null;
			OutputStream tmpOut = null;

			// Get the input and output streams, using temp objects because
			// member streams are final
			try {
				tmpIn = socket.getInputStream();
				tmpOut = socket.getOutputStream();
			} catch (IOException e) { }

			mmInStream = tmpIn;
			mmOutStream = tmpOut;
		}

		public void run() {
			byte[] buffer = new byte[4096];  // buffer store for the stream
			int bytes; // bytes returned from read()

			// Keep listening to the InputStream until an exception occurs
			while (true) {
				try {
					// Read from the InputStream
					bytes = mmInStream.read(buffer);
					// Send the obtained bytes to the UI activity
					myHandler.obtainMessage(1, bytes, -1, buffer).sendToTarget();
				} catch (IOException e) {
					break;
				}
			}
		}

		/* Call this from the main activity to send data to the remote device */
		public void write(String s) {
			try {
				byte[] bytes = s.getBytes();
				mmOutStream.write(bytes);
			} catch (IOException e) { }
		}

		/* Call this from the main activity to shutdown the connection */
		public void cancel() {
			try {
				mmSocket.close();
			} catch (IOException e) { 
				e.printStackTrace();
			}
		}
	}





	private static class MyStaticHandler extends Handler{

	}

	private void killAcceptThread(){
		try {
			if(myAcceptThread != null){
				myAcceptThread.cancel();
				myAcceptThread.stop();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void killConnectThread(){
		try {
			if(myConnectThread != null){
				myConnectThread.cancel();
				myConnectThread.stop();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void killConnectedThread(){
		try {
			if(myConnectedThread != null){
				myConnectedThread.cancel();
				myConnectedThread.stop();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void killThreads(){
		killAcceptThread();
		killConnectThread();
		killConnectedThread();
	}



	void onPerformRequest(RequestBase req){
		//inizializzazione ...
		if(mm != null)
			mm.CloseConnection();

		mm = new MessagingManager();
		boolean connected = mm.ConnectToServer(this); 
		boolean sent = mm.SendRequest(req, this); 
		if(!connected || !sent)
			showFailedAlert("Failed to communicate with the server: network or firewall problem.");

		if(req.getRequestType() == RequestType.GetCardInfo)
			showLoadingDialog("Contacting server", "Fetching information about the incoming card and veryfying owner's identity, please wait...");
		if(req.getRequestType() == RequestType.ChangeOwnership)
			showLoadingDialog("Contacting server", "Trading card, please wait...");
	}
	
	private void showFailedAlert(String message){
		hideLoadingDialog();
		AlertDialog dialogBox = new AlertDialog.Builder(this).create();
		dialogBox.setTitle("An error occourred");
		dialogBox.setMessage(message);
		dialogBox.setButton("Ok",  new DialogInterface.OnClickListener(){

			@Override
			public void onClick(DialogInterface arg0, int arg1) {
				finish();
			}
		});
		dialogBox.show();
	}

	@Override
	void onResponseReceived(Object sender, TypedResponseReceivedEventArgs<ResponseWrapper> e) {
		hideLoadingDialog();
		ResponseBase resp = e.getResponseMessage().getResponse();
		if(resp.getResponseType() == ResponseType.GetCardInfo){
			GetCardInfoResponse r = (GetCardInfoResponse)resp;

			if(!r.hasOwner){
				myConnectedThread.write("failed$" + FAILED_CARD_NOT_AUTHENTICATED);
				showFailedPopup(FAILED_CARD_NOT_AUTHENTICATED);
			}
			else if(SecurityUtilities.verifySignature((r.cardSN + r.cardID + myAccountInfo.getAsString(Constants.ACCOUNT_EMAIL)).getBytes(), tradeSignature, SecurityUtilities.Bin2PublicKey(r.ownerPubKey))){
				myCardInfoResponse = r;
				showConfirmationPopup();
			}
			else{
				myConnectedThread.write("failed$" + FAILED_BAD_SIGNATURE);
				showFailedPopup(FAILED_BAD_SIGNATURE);
			}			
		}

		if(resp.getResponseType() == ResponseType.ChangeOwnership){
			ChangeOwnershipResponse r = (ChangeOwnershipResponse)resp;
			if(!r.error){
				myNewCardInfo = r.newCardInfo;
				myConnectedThread.write("accepted");
				showAcceptedPopup();
			}
			else{
				myConnectedThread.write("failed$" + FAILED_SERVER_REFUSED);
				showFailedPopup(FAILED_SERVER_REFUSED);
			}
		}

	}

	@Override
	public void onLocationObtained() {
		hideLoadingDialog();
		onPerformRequest(new ChangeOwnershipRequest(
				myCardInfoResponse.cardSN,
				myCardInfoResponse.cardID, 
				myAccountInfo.getAsString(Constants.ACCOUNT_EMAIL),
				tradeSignature,
				myGeoLocationHelper.getLatitude(),
				myGeoLocationHelper.getLongitude())
				);


	}

	public static ContentValues buildCardValuesFromResponse(GetCardInfoResponse r){
		ContentValues card = new ContentValues();
		card.put(CARD_SN, r.cardSN);
		card.put(CARD_NAME, r.cardName);
		card.put(CARD_STATS,r.cardStats);
		card.put(CARD_SPECIAL, r.cardSpecial);
		card.put(CARD_CATEGORY, r.cardCategory);
		card.put(CARD_CATEGORY_NAME, r.categoryName);
		card.put(CARD_SUBCATEGORY,r.cardSubCategory);
		card.put(CARD_SUBCATEGORY_NAME, r.subCategoryName);
		card.put(CARD_PREVIEW, r.cardPreview);
		return card;
	}

	public static ContentValues buildUniqueCardValuesFromResponse(GetCardInfoResponse r){
		ContentValues unique = new ContentValues();
		unique.put(UNIQUECARD_SN,r.cardSN);
		unique.put(UNIQUECARD_ID,r.cardID);
		unique.put(UNIQUECARD_AUTENTICATED,r.authenticated);
		unique.put(UNIQUECARD_ACTUALOWNER, r.owner);
		unique.put(UNIQUECARD_FIRSTOWNER, r.firstOwner);
		unique.put(UNIQUECARD_FIRSTAUTH, r.firstAuth);
		return unique;

	}

}